use entity::{
    meeting_room::{ColumnTrait, EntityTrait, QueryFilter},
    sea_orm::ConnectionTrait,
    user::{admin, auth, custom},
};

use super::{PasswordError, PwdEncoder, UserNotFound, UserVerifyError};

#[derive(Debug)]
pub struct User {
    pub(crate) id: i64,
    pub name: String,
    pub(crate) ty: UserType,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum UserType {
    Custom,
    Admin,
}

impl User {
    pub fn is_custom(&self) -> bool {
        matches!(self.ty, UserType::Custom)
    }

    pub fn is_admin(&self) -> bool {
        matches!(self.ty, UserType::Admin)
    }
}

impl From<(admin::Model, auth::Model)> for User {
    fn from((admin, auth): (admin::Model, auth::Model)) -> Self {
        Self {
            id: admin.id,
            name: auth.user_name,
            ty: UserType::Admin,
        }
    }
}

impl From<(custom::Model, auth::Model)> for User {
    fn from((custom, auth): (custom::Model, auth::Model)) -> Self {
        Self {
            id: custom.id,
            name: auth.user_name,
            ty: UserType::Custom,
        }
    }
}

impl User {
    pub async fn verify<Db: ConnectionTrait>(
        db: &Db,
        user_name: String,
        raw_pwd: String,
    ) -> Result<auth::Model, UserVerifyError> {
        let auth = auth::Entity::find()
            .filter(auth::Column::UserName.eq(user_name))
            .one(db)
            .await?
            .ok_or(UserNotFound)?;

        if PwdEncoder::verify(raw_pwd, &auth.pwd)? {
            Ok(auth)
        } else {
            Err(PasswordError.into())
        }
    }
}
